package service.security;

import bean.common.CommonResult;
import config.security.JwtTokenUtil;
import dao.mongo.UserRepository;
import entity.mongo.User;
import entity.mongo.security.Authority;
import enumration.AuthorityEnum;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.PageRequest;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.util.ArrayList;
import java.util.List;

@Service
public class UserSecurityService {
    @Autowired
    private PasswordEncoder passwordEncoder;
    @Autowired
    private UserRepository userRepository;

    @Transactional
    public Mono<User> upgrade(String username, AuthorityEnum authorityEnum) {
        if (username == null) {
            return Mono.empty();
        }


        ArrayList<Authority> list = new ArrayList<>();
//<R> Stream<R>     map(Function<? super T, ? extends R> mapper);
//<R> Mono<R>     map(Function<? super T, ? extends R> mapper)

//<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper)
//<R> Mono<R> flatMap(Function<? super T, ? extends Mono<? extends R>> transformer)
        if (authorityEnum.equals(AuthorityEnum.VIP)) {
            list.add(new Authority(AuthorityEnum.COMMON));
            list.add(new Authority(AuthorityEnum.VIP));
        } else if (AuthorityEnum.SUPER_VIP.equals(authorityEnum)) {
            list.add(new Authority(AuthorityEnum.COMMON));
            list.add(new Authority(AuthorityEnum.VIP));
            list.add(new Authority(AuthorityEnum.SUPER_VIP));
        }
        return userRepository.findByUsername(username).flatMap(dbUser -> {
            if (dbUser == null) {
                return Mono.empty();
            }
            dbUser.setAuthorities(list);
            return userRepository.save(dbUser);
        });
    }

    @Transactional
    public Mono<CommonResult<User>> register(User user) {
        Mono<User> userMono = queryUser(user.getUsername());
        if (userMono.block() != null) {
            return Mono.just(CommonResult.failed("exist"));
        }
        List<Authority> authorities = new ArrayList<>();
        Authority authority = new Authority();
        authority.setAuthorityName(AuthorityEnum.COMMON);
        authorities.add(authority);
        user.setAuthorities(authorities);
        user.setPassword(passwordEncoder.encode(user.getPassword()));
        Mono<User> save = userRepository.save(user);
        return save.map(CommonResult::success);
    }

    public Mono<CommonResult<String>> login(User user) {
        if (user == null || user.getUsername() == null || user.getPassword() == null) {
            return Mono.just(CommonResult.failed("参数错误"));
        }
        Mono<User> userMono = queryUser(user.getUsername());

        return userMono.flatMap(dbUser -> {
            if (passwordEncoder.matches(user.getPassword(), dbUser.getPassword())) {
                return Mono.just(CommonResult.success(JwtTokenUtil.generateToken(dbUser)));
            } else {
                return Mono.just(CommonResult.failed("username or password is invalid"));
            }
        });
    }

    private Mono<User> queryUser(String username) {
        User condition = new User();
        condition.setUsername(username);
        Example<User> example = Example.of(condition);
        return userRepository.findOne(example);
    }

    public Flux<User> userList() {
        PageRequest pageRequest = PageRequest.of(0, 2);
        Flux<User> all = userRepository.findByUsernameOrderByCreateTime("admin", pageRequest);
        return all;
    }
}
